/*
 * ﻿Copyright (C) 2011-2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.aspectjutil.eventmanager;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility class for testing aspectjutil-eventmanager module.
 * <ul>
 * <li>Contains factory method for test models what can be found under 
 * com.newmainsoftech.aspectjutil.eventmanager.testmodels package of aspectjutil-eventmanager module.<br />
 * Those factory method loads corresponding test model via newly instantiated classloader each time. 
 * This is necessary in order to avoid to get onEventMethodMap and preEventMethodMap member fields of 
 * EventHandler class dirty.
 * </li> 
 * </ul>
 * 
 * Requirement: The system properties of what names defined by below member fields need to be pre-defined 
 * for location of class files of those test models in order to load test model class from there directly, 
 * instead of using classpath:
 * <ul>
 * <li>{@link #AspectJUtilAdviseUtilClassesDirPropertyName}</li>
 * <li>{@link #AspectJUtilEventManagerClassesDirPropertyName}</li>
 * <li>{@link #AspectJUtilEventManagerTestClassesDirPropertyName}</li>
 * </ul>
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 */
public class EventManagerTestUtils {
	protected static final Logger logger 
	= LoggerFactory.getLogger( EventManagerTestUtils.class);
	
	public static String getEventTraceListDump( List<String> eventTraceList) {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append( "Executed listeners:");
		if ( eventTraceList.size() > 0) {
			for( int eventTraceListIndex = 0; eventTraceListIndex < eventTraceList.size(); eventTraceListIndex++) {
				String listenerStr = eventTraceList.get( eventTraceListIndex);
				stringBuffer.append(
						String.format(
								"%n%1$c%2$d: %3$s",
								'\t',
								eventTraceListIndex,
								listenerStr.substring( 
										listenerStr.indexOf( "]: ") + 2, listenerStr.length() - 2)
								)
						);
			} // for
		}
		else {
			stringBuffer.append( " None");
		}
		return stringBuffer.toString();
	} // public static String getEventTraceListDump( List<String> eventTraceList)
	
	// ChildDelegationClassLoader factory ---------------------------------------------------------
	protected static class ChildDelegationClassLoader extends URLClassLoader {
		public ChildDelegationClassLoader( URL[] urls) {
			super( urls);
		}
		public ChildDelegationClassLoader( URL[] urls, ClassLoader parent) {
			super( urls, parent);
		}
		
		public void addURL( URL url) {
			super.addURL( url);
		}
		
		/* Override the parent-first delegation behavior to child-first delegation behavior 
		 * (non-Javadoc)
		 * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
		 */
		@Override
		protected Class<?> loadClass( String name, boolean resolve) throws ClassNotFoundException {
			if ( logger.isDebugEnabled()) {
				logger.debug( "Loading class:" + name);
			}
			
			Class<?> classObj = findLoadedClass( name);
			if ( classObj == null) {
				try {
					classObj = findClass( name);
					if ( logger.isDebugEnabled()) {
						logger.debug( "Loaded class:" + classObj.getName());
					}
				}
				catch( ClassNotFoundException exception) { // Ignore
				}
			}
			
			if ( classObj == null) {
				ClassLoader parentClassLoader = getParent();
				if ( parentClassLoader != null) {
					if ( logger.isDebugEnabled()) {
						logger.debug( 
								String.format(
										"To load %1$s class, delegating to parent class loader: %2$s",
										name, 
										parentClassLoader.toString()
										)
								);
					}
					classObj = parentClassLoader.loadClass( name);
				}
				else {
					if ( logger.isDebugEnabled()) {
						logger.debug( 
								String.format(
										"To load %1$s class, delegating to system class loader",
										name
										)
								);
					}
					classObj = getSystemClassLoader().loadClass( name);
				}
			}
			
			if ( resolve) {
				resolveClass( classObj);
			}
			
			return classObj;
		}
		
		@Override
		public Class<?> loadClass( String name) throws ClassNotFoundException {
			return loadClass( name, false);
		}
	} // protected static class ChildDelegationClassLoader extends URLClassLoader
	
	public final static String AspectJUtilAdviseUtilClassesDirPropertyName 
	= "aspectJUtilAdviseUtilClassesDir";
	public final static String AspectJUtilEventManagerClassesDirPropertyName 
	= "aspectJUtilAdviseUtilClassesDir";
	public final static String AspectJUtilEventManagerTestClassesDirPropertyName 
	= "aspectJUtilEventManagerTestClassesDir";
	
	/**
	 * 
	 * @return
	 * @throws Throwable
	 */
	public static ClassLoader childDelegationClassLoaderFactory() throws Throwable {
		String adviseUtilClassesDirStr 
		= System.getProperty( AspectJUtilAdviseUtilClassesDirPropertyName);
		String eventManagerClassesDirStr 
		= System.getProperty( AspectJUtilEventManagerClassesDirPropertyName);
		String eventManagerTestClassesDirStr 
		= System.getProperty( AspectJUtilEventManagerTestClassesDirPropertyName);
		boolean isEventManagerBinaryLocationPropertyDefined = true;
			for( 
					int count = 0; 
					( (adviseUtilClassesDirStr == null) 
						|| ( eventManagerClassesDirStr == null) 
						|| ( eventManagerTestClassesDirStr == null)); 
					count++) 
			{
				if ( count > 0) {
					isEventManagerBinaryLocationPropertyDefined = false;
					break;
				}
				
				URL url = EventManagerTestUtils.class.getResource( "/AspectJUtil.properties");
				if ( url != null) {
					InputStream inputStream = url.openStream();
					Properties poroperties = new Properties();
					poroperties.load( inputStream);
					
					adviseUtilClassesDirStr
					= poroperties.getProperty( AspectJUtilAdviseUtilClassesDirPropertyName);
					eventManagerClassesDirStr 
					= poroperties.getProperty( AspectJUtilEventManagerClassesDirPropertyName);
					eventManagerTestClassesDirStr 
					= poroperties.getProperty( AspectJUtilEventManagerTestClassesDirPropertyName);
				}
			} // for
			if ( !isEventManagerBinaryLocationPropertyDefined) {
				File projectTopDir;
					File currentDir = new File( ".");
						// current directory must be either aspectjutil-eventmanager-test module directory or Maven project top directory
						String currentDirStr = currentDir.getCanonicalFile().toURI().toString();
							if ( currentDirStr.endsWith( "/")) {
								currentDirStr = currentDirStr.substring( 0, ( currentDirStr.length() - 1));
							}
							if ( currentDirStr.endsWith( "/aspectjutil-eventmanager-test")) {
								projectTopDir = new File( "..");
							}
							else {
								projectTopDir = currentDir;
							}
				String projectTopDirStr = projectTopDir.getCanonicalFile().toURI().toString();
					if ( !projectTopDirStr.endsWith( "/")) {
						projectTopDirStr = projectTopDirStr + "/";
					}
					
				String adviseUtilModuleDirStr = projectTopDirStr + "aspectjutil-adviseutil";
					adviseUtilClassesDirStr = adviseUtilModuleDirStr + "/target/classes/";
						adviseUtilClassesDirStr
						= (new File( new URI( adviseUtilClassesDirStr))).getCanonicalPath();
				
				String eventmanagerModuleDirStr = projectTopDirStr + "aspectjutil-eventmanager";
					eventManagerClassesDirStr = eventmanagerModuleDirStr + "/target/classes/";
						eventManagerClassesDirStr 
						= (new File( new URI( eventManagerClassesDirStr))).getCanonicalPath();
					eventManagerTestClassesDirStr = eventmanagerModuleDirStr + "/target/test-classes";
						eventManagerTestClassesDirStr
						= (new File( new URI( eventManagerTestClassesDirStr))).getCanonicalPath();
			}
		
		File adviseUtilClassesDir = new File( adviseUtilClassesDirStr);
			if ( !adviseUtilClassesDir.exists()) {
				String message 
				= adviseUtilClassesDirStr + " directory (where should contain classes of " 
						+ "aspectjutil-adviseutil artifact) does not exist.";
				throw new NullPointerException( message);
			}
		
		File eventManagerClassesDir = new File( eventManagerClassesDirStr);
			if ( !eventManagerClassesDir.exists()) {
				String message 
				= eventManagerClassesDirStr + " directory (where should contain classes of " 
						+ "aspectjutil-eventmanager artifact) does not exist.";
				throw new NullPointerException( message);
			}
		File eventManagerTestClassesDir = new File( eventManagerTestClassesDirStr);
			if ( !eventManagerTestClassesDir.exists()) {
				String message 
				= eventManagerTestClassesDirStr + " directory (where should contain test-classes of " 
						+ "aspectjutil-eventmanager artifact) does not exist.";
				throw new NullPointerException( message);
			}
		
		ChildDelegationClassLoader childDelegationClassLoader
		= new ChildDelegationClassLoader(
				new URL[]{
						adviseUtilClassesDir.toURI().toURL(),
						eventManagerClassesDir.toURI().toURL(),
						eventManagerTestClassesDir.toURI().toURL()
				}
				);
		
		return childDelegationClassLoader;
	}
	// --------------------------------------------------------------------------------------------
	
	// EventInfo factory methods ------------------------------------------------------------------
	public static final String EventInfoClassName = "com.newmainsoftech.aspectjutil.eventmanager.EventInfo";
	public static Class<?> getEventInfoClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventInfoClassName);
	}
	public static Method getEventInfoGetTriggeredEventMethod( 
			Class eventInfoLineageClass) throws Throwable {
		Method method 
		= eventInfoLineageClass.getDeclaredMethod( "getTriggeredEvent", new Class[]{});
		return method;
	}
	public static Method getEventInfoGetEventerInfoMethod( Class eventInfoLineageClass) throws Throwable {
		Method method 
		= eventInfoLineageClass.getDeclaredMethod( "getEventerInfo", new Class[]{});
		return method;
	}
	public static Object getEventerInfo( Object eventInfoObj) throws Throwable {
		Method method 
		= eventInfoObj.getClass().getDeclaredMethod( "getEventerInfo", new Class[]{});
		return method.invoke( eventInfoObj, new Object[]{});
	}
	
	
	public static final String EventerInfoClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.EventInfo$EventerInfo";
	public static Class<?> getEventerInfoClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventerInfoClassName);
	}
	public static Object getEventerObjOfEventerInfo( Object eventerInfo) throws Throwable {
		if ( logger.isDebugEnabled()) {
			if ( !EventerInfoClassName.equals( eventerInfo.getClass().getName())) {
				logger.debug(
						String.format(
								"Expected %1$s type object as argument but provided one was %2$s type.",
								EventerInfoClassName, 
								eventerInfo.getClass().getName()
								)
						);
			}
		}
		Method method 
		= eventerInfo.getClass().getDeclaredMethod( "getEventerObj", new Class[]{});
		return method.invoke( eventerInfo, new Object[]{});
	}
	public static Method getEventerMethodOfEventerInfo( Object eventerInfo) throws Throwable {
		if ( logger.isDebugEnabled()) {
			if ( !EventerInfoClassName.equals( eventerInfo.getClass().getName())) {
				logger.debug(
						String.format(
								"Expected %1$s type object as argument but provided one was %2$s type.",
								EventerInfoClassName, 
								eventerInfo.getClass().getName()
								)
						);
			}
		}
		Method method 
		= eventerInfo.getClass().getDeclaredMethod( "getEventerMethod", new Class[]{});
		return (Method)method.invoke( eventerInfo, new Object[]{});
	}
	public static Field getEventerFieldOfEventerInfo( Object eventerInfo) throws Throwable {
		if ( logger.isDebugEnabled()) {
			if ( !EventerInfoClassName.equals( eventerInfo.getClass().getName())) {
				logger.debug(
						String.format(
								"Expected %1$s type object as argument but provided one was %2$s type.",
								EventerInfoClassName, 
								eventerInfo.getClass().getName()
								)
						);
			}
		}
		Method method 
		= eventerInfo.getClass().getDeclaredMethod( "getEventerField", new Class[]{});
		return (Field)method.invoke( eventerInfo, new Object[]{});
	}
	
	
	public static final String EventerTypeEnumName 
	= "com.newmainsoftech.aspectjutil.eventmanager.EventInfo$EventerType";
	public static Class<?> getEventerTypeEnum( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventerTypeEnumName);
	}
	public static Object getEventerType( String eventerType, ClassLoader classLoader) throws Throwable {
		Class<?> eventerTypeEnum = classLoader.loadClass( EventerTypeEnumName);
		Method valueOfvalueOfMethod 
		= eventerTypeEnum.getDeclaredMethod( "valueOf", new Class[]{ String.class});
		return valueOfvalueOfMethod.invoke( null, new Object[]{ eventerType});
	}
	public static Object getEventerTypeOfEventerInfo( Object eventerInfo) throws Throwable {
		Method method 
		= eventerInfo.getClass().getDeclaredMethod( "getEventerType", new Class[]{});
		return method.invoke( eventerInfo, new Object[]{});
	}
	// --------------------------------------------------------------------------------------------
	
	// SubscriberMethodUnit factory methods -------------------------------------------------------
	public static final String SubscriberMethodUnitClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.SubscriberMethodUnit";
	public static Class<?> getSubscriberMethodUnitClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( SubscriberMethodUnitClassName);
	}
	public static Object subscriberMethodUnitFactory( 
			ClassLoader classLoader, Method method, Class<?> methodClass, boolean threadAware, int turn) 
	throws Throwable 
	{
		Class<?> subscriberMethodUnitClass = getSubscriberMethodUnitClass( classLoader);
		Constructor<?> constructor 
		= subscriberMethodUnitClass.getConstructor( Method.class, Class.class, Boolean.TYPE, Integer.TYPE);
		return constructor.newInstance( method, methodClass, threadAware, turn);
	}
	// --------------------------------------------------------------------------------------------
	
	// EventTraceSupporter factory methods --------------------------------------------------------
	public static final String EventTraceSupporterClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventTraceSupporter";
	
	public static Class<?> getEventTraceSupporterClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventTraceSupporterClassName);
	}
	
	public static List<String> getEventTraceListOfEventTraceSupporter( 
			Class<?> eventTraceSupporterClass) throws Throwable {
		if ( logger.isDebugEnabled()) {
			if ( !EventTraceSupporterClassName.equals( eventTraceSupporterClass.getName())) {
				logger.debug(
						String.format(
								"Expected %1$s class as argument but provided one was %2$s class.",
								EventTraceSupporterClassName, 
								eventTraceSupporterClass.getName()
								)
						);
			}
		}
		Method getEventTraceListMethod 
		= eventTraceSupporterClass.getDeclaredMethod( "getEventTraceList", new Class[]{});
		return (List<String>)getEventTraceListMethod.invoke( null, new Object[]{});
	}
	
	public static void setEventTraceListOfEventTraceSupporter( 
			Class<?> eventTraceSupporterClass, List<String> eventTraceList) throws Throwable {
			if ( !EventTraceSupporterClassName.equals( eventTraceSupporterClass.getName())) {
				if ( logger.isDebugEnabled()) {
				logger.debug(
						String.format(
								"Expected %1$s class as argument but provided one was %2$s class.",
								EventTraceSupporterClassName, 
								eventTraceSupporterClass.getName()
								)
						);
			}
		}
		Method setEventTraceListMethod 
		= eventTraceSupporterClass.getDeclaredMethod( "setEventTraceList", List.class);
		setEventTraceListMethod.invoke( null, eventTraceList);
	} // public static void setEventTraceListOfEventTraceSupporter(
	
	public static void setEventerTraceListOfEventTraceSupporter( 
			Class<?> eventTraceSupporterClass, List<Object> eventerTraceList) throws Throwable {
			if ( !EventTraceSupporterClassName.equals( eventTraceSupporterClass.getName())) {
				if ( logger.isDebugEnabled()) {
				logger.debug(
						String.format(
								"Expected %1$s class as argument but provided one was %2$s class.",
								EventTraceSupporterClassName, 
								eventTraceSupporterClass.getName()
								)
						);
			}
		}
		Method method 
		= eventTraceSupporterClass.getDeclaredMethod( "setEventerTraceList", List.class);
		method.invoke( null, eventerTraceList);
	} // public static void setEventerTraceListOfEventTraceSupporter(
	
	public static void setEventResultTraceListOfEventTraceSupporter( 
			Class<?> eventTraceSupporterClass, List<Object> eventResultTraceList) throws Throwable {
			if ( !EventTraceSupporterClassName.equals( eventTraceSupporterClass.getName())) {
				if ( logger.isDebugEnabled()) {
				logger.debug(
						String.format(
								"Expected %1$s class as argument but provided one was %2$s class.",
								EventTraceSupporterClassName, 
								eventTraceSupporterClass.getName()
								)
						);
			}
		}
		Method method 
		= eventTraceSupporterClass.getDeclaredMethod( "setEventResultTraceList", List.class);
		method.invoke( null, eventResultTraceList);
	} // public static void setEventResultTraceListOfEventTraceSupporter(
	
	public static void setTriggeredEventTraceListOfEventTraceSupporter( 
			Class<?> eventTraceSupporterClass, List<Class<?>> triggeredEventTraceList) throws Throwable {
			if ( !EventTraceSupporterClassName.equals( eventTraceSupporterClass.getName())) {
				if ( logger.isDebugEnabled()) {
				logger.debug(
						String.format(
								"Expected %1$s class as argument but provided one was %2$s class.",
								EventTraceSupporterClassName, 
								eventTraceSupporterClass.getName()
								)
						);
			}
		}
		Method method 
		= eventTraceSupporterClass.getDeclaredMethod( "setTriggeredEventTraceList", List.class);
		method.invoke( null, triggeredEventTraceList);
	} // public static void setEventResultTraceListOfEventTraceSupporter(
	// --------------------------------------------------------------------------------------------
	
	// SampleEventClass factory methods -----------------------------------------------------------
	public static final String SampleEventClassClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.SampleEventClass";
	public static Class<?> getSampleEventClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( SampleEventClassClassName);
	}
	public static final String CalculationEventClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.SampleEventClass$CalculationEvent";
	public static Class<?> getCalculationEventClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( CalculationEventClassName);
	}
	public static final String PriceChangeClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.SampleEventClass$PriceChange";
	public static Class<?> getPriceChangeClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( PriceChangeClassName);
	}
	public static final String OverridenCalculationEventClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.SampleEventClass$OverridenCalculationEvent";
	public static Class<?> getOverridenCalculationEventClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( OverridenCalculationEventClassName);
	}
	// --------------------------------------------------------------------------------------------
	
	// EventRecipient factory methods -------------------------------------------------------------
	public static final String EventRecipientClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventRecipient";
	public static Class<?> getEventRecipientClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventRecipientClassName);
	}
	public static Object eventRecipientFactory( ClassLoader classLoader) throws Throwable {
		Class<?> eventRecipientClass = getEventRecipientClass( classLoader);
		return eventRecipientClass.newInstance();
	}
	public static Method getOnCalculationCompletionMethodOfEventRecipient( 
			ClassLoader classLoader, Class<?> eventRecipientLineageClass) throws Throwable {
		Class<?> eventInfoClass = getEventInfoClass( classLoader);
		Method onCalculationCompletionMethod 
		= eventRecipientLineageClass.getDeclaredMethod( "onCalculationCompletion", eventInfoClass);
		onCalculationCompletionMethod.setAccessible( true);
		return onCalculationCompletionMethod;
	}
	// --------------------------------------------------------------------------------------------
	
	// EventRecipientChild factory methods --------------------------------------------------------
	public static final String EventRecipientChildClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventRecipientChild";
	public static Class<?> getEventRecipientChildClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventRecipientChildClassName);
	}
	public static Object eventRecipientChildFactory( ClassLoader classLoader) throws Throwable {
		Class<?> eventRecipientChildClass = getEventRecipientChildClass( classLoader);
		return eventRecipientChildClass.newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// EventRecipientGrandChild factory methods ---------------------------------------------------
	public static final String EventRecipientGrandChildClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventRecipientGrandChild";
	public static Class<?> getEventRecipientGrandChildClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventRecipientGrandChildClassName);
	}
	public static Object eventRecipientGrandChildFactory( ClassLoader classLoader) throws Throwable {
		Class<?> eventRecipientGrandChildClass = getEventRecipientGrandChildClass( classLoader);
		return eventRecipientGrandChildClass.newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// ChildEventRecipient2 factory methods -------------------------------------------------------
	public static final String ChildEventRecipient2ClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.ChildEventRecipient2";
	public static Class<?> getChildEventRecipient2Class( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( ChildEventRecipient2ClassName);
	}
	public static Object childEventRecipient2Factory( ClassLoader classLoader) throws Throwable {
		Class<?> childEventRecipient2Class = getChildEventRecipient2Class( classLoader);
		return childEventRecipient2Class.newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// ChildEventRecipient3 factory methods -------------------------------------------------------
	// ChildEventRecipient3 is not extension of EventRecipient
	public static final String ChildEventRecipient3ClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.ChildEventRecipient3";
	public static Class<?> getChildEventRecipient3Class( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( ChildEventRecipient3ClassName);
	}
	public static Object childEventRecipient3Factory( ClassLoader classLoader) throws Throwable {
		Class<?> childEventRecipient3Class = getChildEventRecipient3Class( classLoader);
		return childEventRecipient3Class.newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// PreEventRecipient factory methods -------------------------------------------------------------
	public static final String PreEventRecipientClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.PreEventRecipient";
	public static Class<?> getPreEventRecipientClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( PreEventRecipientClassName);
	}
	public static Object preEventRecipientFactory( ClassLoader classLoader) throws Throwable {
		Class<?> preEventRecipientClass = getPreEventRecipientClass( classLoader);
		return preEventRecipientClass.newInstance();
	}
	public static Method getOnCalculationStartMethodOfPreEventRecipient( 
			ClassLoader classLoader, Class<?> preEventRecipientLineageClass) throws Throwable {
		Class<?> eventInfoClass = getEventInfoClass( classLoader);
		Method onCalculationStartMethod 
		= preEventRecipientLineageClass.getDeclaredMethod( "onCalculationStart", eventInfoClass);
		onCalculationStartMethod.setAccessible( true);
		return onCalculationStartMethod;
	}
	// --------------------------------------------------------------------------------------------
	
	// EventProducer factory methods --------------------------------------------------------------
	public static final String EventProducerClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventProducer";
	public static Class<?> getEventProducerClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventProducerClassName);
	}
	public static Object eventProducerFactory( ClassLoader classLoader) throws Throwable {
		return getEventProducerClass( classLoader).newInstance();
	}
	protected static boolean isEventProducerClass( Class<?> classObj) {
		return EventProducerClassName.equals( classObj.getName());
	}
	public static Method getEventProducerCalculateMethod( 
			Class<?> eventProducerLineageClass) throws Throwable {
/*		if ( !isEventProducerClass( eventProducerClass)) {
			throw new NoSuchMethodException(
					String.format(
							"Argument must be %1$s class.%nBut actual argument was %2$S", 
							EventProducerClassName, 
							eventProducerClass.getName()
							)
					);
		}
*/
		Method calculateMethod 
		= eventProducerLineageClass.getDeclaredMethod( "calculate", Integer.TYPE, Integer.TYPE);
		calculateMethod.setAccessible( true);
		return calculateMethod;
	}
	public static Method getEventProducerSetPriceMethod( 
			Class<?> eventProducerLineageClass) throws Throwable {
/*		if ( !isEventProducerClass( eventProducerClass)) {
			throw new NoSuchMethodException(
					String.format(
							"Argument must be %1$s class.%nBut actual argument was %2$S", 
							EventProducerClassName, 
							eventProducerClass.getName()
							)
					);
		}
*/
		Method setPriceMethod 
		= eventProducerLineageClass.getDeclaredMethod( "setPrice", Integer.TYPE);
		setPriceMethod.setAccessible( true);
		return setPriceMethod;
	}
	// --------------------------------------------------------------------------------------------
	
	// ChildEventProducer1 factory methods --------------------------------------------------------
	public static final String ChildEventProducer1ClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.ChildEventProducer1";
	public static Class<?> getChildEventProducer1Class( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( ChildEventProducer1ClassName);
	}
	public static Object childEventProducer1Factory( ClassLoader classLoader) throws Throwable {
		return getChildEventProducer1Class( classLoader).newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// ChildEventProducer2 factory methods --------------------------------------------------------
	public static final String ChildEventProducer2ClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.ChildEventProducer2";
	public static Class<?> getChildEventProducer2Class( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( ChildEventProducer2ClassName);
	}
	public static Object childEventProducer2Factory( ClassLoader classLoader) throws Throwable {
		return getChildEventProducer2Class( classLoader).newInstance();
	}
	protected static boolean isChildEventProducer2Class( Class<?> classObj) {
		return ChildEventProducer2ClassName.equals( classObj.getName());
	}
	// --------------------------------------------------------------------------------------------
	
	// ChildEventProducer3 factory methods --------------------------------------------------------
	public static final String ChildEventProducer3ClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.ChildEventProducer3";
	public static Class<?> getChildEventProducer3Class( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( ChildEventProducer3ClassName);
	}
	public static Object childEventProducer3Factory( ClassLoader classLoader) throws Throwable {
		return getChildEventProducer3Class( classLoader).newInstance();
	}
	// --------------------------------------------------------------------------------------------
	
	// EventProducerByStaticField factory methods -------------------------------------------------
	public static final String EventProducerByStaticFieldClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventProducerByStaticField";
	public static Class<?> getEventProducerByStaticFieldClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventProducerByStaticFieldClassName);
	}
	public static Method getSetPriceMethodOfEventProducerByStaticField( 
			ClassLoader classLoader) throws Throwable {
		Class<?> eventProducerByStaticFieldClass = getEventProducerByStaticFieldClass( classLoader);
		Method setPriceMethod 
		= eventProducerByStaticFieldClass.getDeclaredMethod( "setPrice", Integer.TYPE);
		setPriceMethod.setAccessible( true);
		return setPriceMethod;
	}
	// --------------------------------------------------------------------------------------------
	
	// EventProducerWrapper factory methods --------------------------------------------------------------------------------------------
	public static final String EventProducerWrapperClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventProducerWrapper";
	public static Class<?> getEventProducerWrapperClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventProducerWrapperClassName);
	}
	public static Object eventProducerWrapperFactory( ClassLoader classLoader) throws Throwable {
		Class<?> eventProducerWrapperClass = getEventProducerWrapperClass( classLoader);
		return eventProducerWrapperClass.newInstance();
	}
	public static Method getEventProducerWrapperCalculateMethod( 
			Class<?> eventProducerWrapperLineageClass) throws Throwable {
		Method calculateMethod 
		= eventProducerWrapperLineageClass.getDeclaredMethod( "calculate", Integer.TYPE, Integer.TYPE);
		calculateMethod.setAccessible( true);
		return calculateMethod;
	}
	public static Method getEventProducerWrapperSetPriceMethod( 
			Class<?> eventProducerWrapperLineageClass) throws Throwable {
		Method setPriceMethod 
		= eventProducerWrapperLineageClass.getDeclaredMethod( "setPrice", Integer.TYPE);
		setPriceMethod.setAccessible( true);
		return setPriceMethod;
	}
	// --------------------------------------------------------------------------------------------
	
	// EventProducerWrapperAspect factory methods -------------------------------------------------
	public static final String EventProducerWrapperAspectClassName 
	= "com.newmainsoftech.aspectjutil.eventmanager.testmodels.EventProducerWrapperAspect";
	public static Class<?> getEventProducerWrapperAspectClass( ClassLoader classLoader) throws Throwable {
		return classLoader.loadClass( EventProducerWrapperAspectClassName);
	}
	public static Method getEventProducerWrapperAspectGetEventInfoMethod( 
			Class<?> eventProducerWrapperAspectLineageClass) throws Throwable {
		Method getEventInfoMethod 
		= eventProducerWrapperAspectLineageClass.getDeclaredMethod( "getEventInfo", new Class<?>[]{});
		getEventInfoMethod.setAccessible( true);
		return getEventInfoMethod;
	}
	// --------------------------------------------------------------------------------------------
	
//TODO Once I finish developing MavenPath in ant-util project I may use it to provide locations of class files of test models.
	
}
